﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using CRFSharp;
using WordSeg;

namespace wordseg_demo
{
    class Program
    {
        static string strConfigFileName = "";
        static string strLexicalFileName = "";
        static string strModelFileName = "";
        static string strPinyinMapFileName = "";
        static string strFeatureGeneratorDLL = "";
        static string strFeatureGeneratorNamespace = "";
        static string strInputFileName = "";
        static string strOutputFileName = "";

        static bool bPinYin = false;

        static WordSeg.WordSeg wordseg = null;
        static WordSeg.Tokens tokens = null;
        static WordSeg.PinYinUtils pinyinUtils = null;
        static bool bCRFModel = false;

        static void ParseIniFile(string strIniFileName)
        {
            StreamReader sr = new StreamReader(strIniFileName);
            while (sr.EndOfStream == false)
            {
                string strLine = sr.ReadLine();
                string[] items = strLine.Split('=');
                string strKey = items[0].Trim().ToLower();
                string strValue = items[1].Trim().ToLower();

                switch (strKey)
                {
                    case "lexicalfilename":
                        strLexicalFileName = strValue;
                        break;
                    case "modelfilename":
                        strModelFileName = strValue;
                        break;
                    case "pinyinmapping":
                        strPinyinMapFileName = strValue;
                        break;
                    case "featuregeneratordll":
                        strFeatureGeneratorDLL = strValue;
                        break;
                    case "featuregeneratornamespace":
                        strFeatureGeneratorNamespace = strValue;
                        break;
                }
            }
            sr.Close();
        }


        static void Usage()
        {
            Console.WriteLine("Word segmentation demo program by Zhongkai Fu (fuzhongkai@gmail.com)");
            Console.WriteLine("WordSeg_demo [parameter list]");
            Console.WriteLine("Parameter list:");
            Console.WriteLine("  -config : configuration file name");
            Console.WriteLine("  -input : the file need to be segmented");
            Console.WriteLine("  -output : the segment result file name");
        }

        static void ParseParameter(string [] args)
        {
            for (int i = 0; i < args.Length; i++)
            {
                args[i] = args[i].ToLower();
            }

            for (int i = 0; i < args.Length;i++)
            {
                string strParameter = args[i].Substring(1);
                if (strParameter == "config")
                {
                    i++;
                    strConfigFileName = args[i];
                }
                else if (strParameter == "input")
                {
                    i++;
                    strInputFileName = args[i];
                }
                else if (strParameter == "output")
                {
                    i++;
                    strOutputFileName = args[i];
                }
                else
                {
                    Console.WriteLine("Invalidated parameter : {0}", args[i]);
                    return;
                }
            }
        }

        static void InitializeWordSeg()
        {
            IGenerateFeature featureGenerator = null;
            if (strFeatureGeneratorDLL.Length > 0 &&
                File.Exists(strFeatureGeneratorDLL) == true)
            {
                Console.WriteLine("Loading external DLL: {0}", strFeatureGeneratorDLL);
                Assembly ass = Assembly.LoadFrom(strFeatureGeneratorDLL);
                if (ass == null)
                {
                    Console.WriteLine("Load {0} failed.", strFeatureGeneratorDLL);
                }
                featureGenerator = ass.CreateInstance(strFeatureGeneratorNamespace) as IGenerateFeature;
                if (featureGenerator == null)
                {
                    Console.WriteLine("Create instance {0} failed.", strFeatureGeneratorNamespace);
                }

                featureGenerator.Initialize();
            }

            //Initialize word segment instance
            wordseg = new WordSeg.WordSeg();

            //Load lexical dictionary with raw text format
            wordseg.LoadLexicalDict(strLexicalFileName, true);

            //Load CRF model with default feature generator
            bCRFModel = false;
            if (strModelFileName.Length > 0)
            {
                bCRFModel = wordseg.LoadModelFile(strModelFileName, featureGenerator);
            }

            //Create tokens which is local-thread structure
            //The max word segment legnth is MAX_SEGMENT_LENGTH
            tokens = wordseg.CreateTokens();

            //Initialize Chinese Pinyin utils instance
            if (strPinyinMapFileName.Length > 0)
            {
                pinyinUtils = new WordSeg.PinYinUtils();
                pinyinUtils.Initialize(strPinyinMapFileName);
                bPinYin = true;
            }
        }

        static void Main(string[] args)
        {
            ParseParameter(args);
            if (strConfigFileName.Length == 0 || strInputFileName.Length == 0 || strOutputFileName.Length == 0)
            {
                Usage();
                return;
            }
            ParseIniFile(strConfigFileName);

            InitializeWordSeg();

            StreamReader sr = new StreamReader(strInputFileName);
            StreamWriter sw = new StreamWriter(strOutputFileName);

            while (sr.EndOfStream == false)
            {
                string strLine = sr.ReadLine();

                //Segment text with both lexical dictionary and CRF model
                wordseg.Segment(strLine, tokens, bCRFModel);
                StringBuilder sb = new StringBuilder();

                //Parse each broken token
                for (int i = 0; i < tokens.tokenList.Count; i++)
                {
                    sb.Append(tokens.tokenList[i].strTerm);

                    string strTags = "";
                    if (tokens.tokenList[i].strTagList.Count > 0)
                    {
                        foreach (string strTag in tokens.tokenList[i].strTagList)
                        {
                            strTags = strTags + "|" + strTag;
                        }
                        strTags = strTags.Substring(1);
                    }
                    else
                    {
                        strTags = "NOR";
                    }

                    if (bPinYin == true)
                    {
                        string strPinYin = pinyinUtils.ConvertTermsIntoPinYin(tokens.tokenList[i].strTerm);
                        sb.Append("[" + strPinYin + ":" + strTags + "]");
                    }
                    else if (strTags != "NOR")
                    {
                        sb.Append("[" + strTags + "]");
                    }

                    sb.Append(" ");
                }
                sw.WriteLine(sb.ToString().Trim());
            }

            sr.Close();
            sw.Close();
        }
    }
}
